package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.product.service.RedisTestService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/***
 * redis缓存操作的测试接口的实现类
 */
@Service
public class RedisTestServiceImpl implements RedisTestService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;

    /**
     * 写操作
     */
    @Override
    public void setRedis() {
        //在redis中使用setnx进行枪锁，解决分布式锁的问题
        //为锁弄一个uuid，避免锁误删的情况
        String uuid = UUID.randomUUID().toString().replace("-", "");
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid);
        //加锁成功
        if (lock) {
            //加锁成功，为锁设置过期时间，解决解锁失败的情况
            redisTemplate.expire("lock", 10, TimeUnit.SECONDS);
            //从redis中获取数据
            Integer java0828 = (Integer) redisTemplate.opsForValue().get("java0828");
            //从redis中取数据，如果有就做+1操作
            if (null != java0828) {
                java0828++;
                redisTemplate.opsForValue().set("java0828", java0828);
            }
            //释放锁优化，取值 --> 判断 --> 删除 ，一步到位lua脚本
            //初始化脚本
            DefaultRedisScript script = new DefaultRedisScript<>();
            script.setScriptText("if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end");
            //执行
            redisTemplate.execute(script, Arrays.asList("lock"), uuid);

//            //判断是否为自己当前的锁
//            String lock1 = (String) redisTemplate.opsForValue().get("lock");
//            if(lock1.equals(uuid)){
//                //避免误删锁，自己只能删除自己的锁
//                redisTemplate.delete("lock");
//            }
        } else {
            //加锁失败
            try {
                Thread.sleep(100);
                setRedis();
            } catch (Exception e) {

            }
        }

    }

    /**
     * 写操作
     */
    @Override
    public void setRedisByRedission() {
        //加锁
        RLock lock = redissonClient.getLock("lock");
        try {
            if (lock.tryLock(100, 100, TimeUnit.SECONDS)) {
                try{
                    //加锁成功，写操作
                    //从redis中获取数据
                    Integer java0828 = (Integer) redisTemplate.opsForValue().get("java0828");
                    //从redis中取数据，如果有就做+1操作
                    if (null != java0828) {
                        java0828++;
                        redisTemplate.opsForValue().set("java0828", java0828);
                    }
                }catch (Exception e){
                    System.out.println("加锁成功,但是处理逻辑出现异常: " + e.getMessage());
                }finally {
                    //释放锁
                    lock.unlock();
                }
            }
        } catch (Exception e) {
            System.out.println("加锁失败,加锁的过程中出现异常:" + e.getMessage());
        }
    }
}
